import { useI18n } from "@/hooks/web/useI18n";
import { usePermission } from "@/hooks/web/usePermission";
import { isArray, isBoolean, isFunction, isString } from "@/utils/is";
import { cloneDeep, isEqual } from "lodash-es";
import {
  computed,
  ComputedRef,
  h,
  Ref,
  ref,
  toRaw,
  unref,
  VNode,
  watch,
} from "vue";
import {
  ACTION_COLUMN_TYPE,
  DEFAULT_ALIGN,
  INDEX_COLUMN_TYPE,
  PAGE_SIZE,
} from "../const";
import { PaginationProps } from "../types/pagination";
import { BasicColumn, BasicTableProps, GetColumnsParams } from "../types/table";
import { Recordable } from "/#/global";

function handleItem(item: BasicColumn<any>, showOverflowTooltip: boolean) {
  const { columnKey, id, children } = item;
  item.align = item.align || DEFAULT_ALIGN;
  if (showOverflowTooltip) {
    if (!columnKey) {
      item.columnKey = id?.toString();
    }
    if (!isBoolean(item.showOverflowTooltip)) {
      // Object.assign(target, ...sources)
      // 参数：target--->目标对象
      //     source--->源对象
      // 返回值：target，即目标对象
      Object.assign(item, {
        showOverflowTooltip,
      });
    }
  }
  if (children && children.length) {
    handleChildren(children, !!showOverflowTooltip);
  }
}
function handleChildren(
  children: BasicColumn<any>[] | undefined,
  showOverflowTooltip: boolean
) {
  if (!children) return;
  children.forEach((item) => {
    const { children } = item;
    handleItem(item, showOverflowTooltip);
    handleChildren(children, showOverflowTooltip);
  });
}

export function useColumns(
  propsRef: ComputedRef<BasicTableProps>,
  getPaginationRef: ComputedRef<boolean | PaginationProps>
) {
  const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<
    BasicColumn<any>[]
  >;
  let cacheColumns = unref(propsRef).columns;

  const getColumnsRef = computed(() => {
    const columns = cloneDeep(unref(columnsRef));
    handleIndexColumn(propsRef, getPaginationRef, columns);
    handleActionColumn(propsRef, columns);
    if (!columns) {
      return [];
    }
    const { showOverflowTooltip } = unref(propsRef);

    columns.forEach((item) => {
      const { renderHeader, slots } = item;

      handleItem(
        item,
        Reflect.has(item, "showOverflowTooltip")
          ? !!item.showOverflowTooltip
          : !!showOverflowTooltip && !renderHeader && !slots
      );
    });
    return columns;
  });

  function isIfShow(column: BasicColumn<any>): boolean {
    const ifShow = column.ifShow;

    let isIfShow = true;

    if (isBoolean(ifShow)) {
      isIfShow = ifShow;
    }
    if (isFunction(ifShow)) {
      isIfShow = ifShow(column);
    }
    return isIfShow;
  }

  const { hasPermission } = usePermission();

  const getViewColumns = computed(() => {
    const viewColumns = sortFixedColumn(unref(getColumnsRef));
    const columns = cloneDeep(viewColumns);
    return columns
      .filter((column) => {
        return hasPermission(column.auth) && isIfShow(column);
      })
      .map((column) => {
        const { slots, id, renderHeader, format, edit, editRow, type } = column;
        // if (!slots || !slots?.title) {
        //   column.slots = { title: `header-${index}`, ...(slots || {}) };
        //   column.customTitle = column.label;
        //   Reflect.deleteProperty(column, "title");
        // }
        // const isDefaultAction = [
        //   INDEX_COLUMN_TYPE,
        //   ACTION_COLUMN_TYPE,
        // ].includes(type!);
        // if (!renderHeader && format && !edit && !isDefaultAction) {
        //   column.renderHeader = ({ column}) => {
        //     return formatCell(column.label, format, column.,column.index);
        //   };
        // }
        // edit table
        // if ((edit || editRow) && !isDefaultAction) {
        //   column.renderHeader = renderEditCell(column);
        // }
        return column;
      });
  });

  // 索引列
  function handleIndexColumn(
    propsRef: ComputedRef<BasicTableProps>,
    getPaginationRef: ComputedRef<boolean | PaginationProps>,
    columns: BasicColumn<any>[]
  ) {
    const { t } = useI18n();

    const { showIndexColumn, indexColumnProps, isTreeTable } = unref(propsRef);

    let pushIndexColumns = false;
    if (unref(isTreeTable)) {
      return;
    }

    columns.forEach(() => {
      const indIndex = columns.findIndex(
        (column) => column.type === INDEX_COLUMN_TYPE
      );
      if (showIndexColumn) {
        pushIndexColumns = indIndex === -1;
      } else if (!showIndexColumn && indIndex !== -1) {
        columns.splice(indIndex, 1);
      }
    });

    if (!pushIndexColumns) return;

    const isFixedLeft = columns.some((item) => item.fixed === "left");

    columns.unshift({
      type: INDEX_COLUMN_TYPE,
      width: 60,
      label: t("component.table.index"),
      align: "center",
      renderHeader: ({ $index }): VNode => {
        const getPagination = unref(getPaginationRef);
        if (isBoolean(getPagination)) {
          return h("div", {}, `${$index + 1}`);
        }
        const { current = 1, pageSize = PAGE_SIZE } = getPagination;
        console.log((current - 1) * pageSize + $index + 1);
        return h(
          "div",
          {},
          ((current < 1 ? 1 : current) - 1) * pageSize + $index + 1
        );
      },
      ...(isFixedLeft
        ? {
            fixed: "left",
          }
        : {}),
      ...indexColumnProps,
    });
  }

  function handleActionColumn(
    propsRef: ComputedRef<BasicTableProps>,
    columns: BasicColumn<any>[]
  ) {
    const { actionColumn } = unref(propsRef);
    if (!actionColumn) return;

    const hasIndex = columns.findIndex(
      (column) => column.type === ACTION_COLUMN_TYPE
    );
    if (hasIndex === -1) {
      columns.push({
        ...columns[hasIndex],
        fixed: "right",
        ...actionColumn,
        type: ACTION_COLUMN_TYPE,
      });
    }
  }

  function getColumns(opt?: GetColumnsParams) {
    const { ignoreIndex, ignoreAction, sort } = opt || {};
    let columns = toRaw(unref(getColumnsRef));
    if (ignoreIndex) {
      columns = columns.filter((item) => item.type !== INDEX_COLUMN_TYPE);
    }
    if (ignoreAction) {
      columns = columns.filter((item) => item.type !== ACTION_COLUMN_TYPE);
    }
    if (sort) {
      columns = sortFixedColumn(columns);
    }

    return columns;
  }

  function setColumns(columnList: Partial<BasicColumn<any>>[] | string[]) {
    const columns = cloneDeep(columnList);
    if (!isArray(columns)) return;

    if (columns.length <= 0) {
      columnsRef.value = [];
      return;
    }

    const firstColumn = columns[0];

    const cacheKeys = cacheColumns.map((item) => item.id);
    if (!isString(firstColumn)) {
      columnsRef.value = columns as BasicColumn<Recordable>[];
    } else {
      // 以下逻辑没有改待定
      const columnKeys = columns as string[];
      const newColumns: BasicColumn<Recordable>[] = [];
      cacheColumns.forEach((item) => {
        newColumns.push({
          ...item,
          defaultHidden: !columnKeys.includes(item.id! || (item.id as string)),
        });
      });

      if (!isEqual(cacheKeys, columns)) {
        newColumns.sort((prev, next) => {
          return (
            columnKeys.indexOf(prev.id as string) -
            columnKeys.indexOf(next.id as string)
          );
        });
      }
      columnsRef.value = newColumns;
    }
  }

  watch(
    () => unref(propsRef).columns,
    (columns) => {
      columnsRef.value = columns;
      cacheColumns = columns?.filter((item) => !item.type) ?? [];
    }
  );
  function getCacheColumns() {
    return cacheColumns;
  }
  return {
    getViewColumns,
    getColumns,
    setColumns,
    getCacheColumns,
  };
}

function sortFixedColumn(columns: BasicColumn<any>[]) {
  const fixedLeftColumns: BasicColumn<any>[] = [];
  const fixedRightColumns: BasicColumn<any>[] = [];
  const defColumns: BasicColumn<any>[] = [];
  for (const column of columns) {
    if (column.fixed === "left") {
      fixedLeftColumns.push(column);
      continue;
    }
    if (column.fixed === "right") {
      fixedRightColumns.push(column);
      continue;
    }
    defColumns.push(column);
  }
  return [...fixedLeftColumns, ...defColumns, ...fixedRightColumns].filter(
    (item) => !item.defaultHidden
  );
}
